package com.nju.crawler.executor;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONNull;
import cn.hutool.json.JSONObject;
import com.nju.crawler.repository.PersistService;
import com.nju.crawler.storage.FileUtil;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @authorliyunfei
 * @date2022/11/11
 **/
public class CrawlGithubTask implements Runnable,Task{
    private static final String USER_INFO_URL = "https://api.github.com/users?repos%3E0&since=";// index
    private static final String REPO_INFO_URL = "https://api.github.com/users/username/repos";

    // 灵活、动态 -- 暂时先通过传参，后续可通过存MySQL动态去修改
    private static final String LIMIT_TOKEN = "token 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";
    private static final String SAVE_PATH_PREFIX = "E:\\JavaProjects\\CourseProjects\\cloud-compute-lab\\cloud-compute-crawler\\src\\main\\resources\\files";


    private volatile boolean isStop = false;
    private String name;
    private Integer startIndex;
    private String savePathPrefix;
    private PersistService persistService;

    public CrawlGithubTask( String name,Integer startIndex,String savePathPrefix) {//boolean isStop,
        this.name = name;
        this.startIndex = startIndex;
        this.savePathPrefix = savePathPrefix;
    }

    public void setPersistService(PersistService persistService) {
        this.persistService = persistService;
    }

    @Override
    public void run() {
        execute();
    }

    @Override
    public void init() {
        //
    }

    void crawl(int index){

        // 处理超时、反应结果
        String json = HttpUtil.createGet(USER_INFO_URL+index)
                .header("Authorization",LIMIT_TOKEN)
                .execute()
                .body();


        if(json.contains("limit")){
            // 限流--，请切换token执行


        }


        JSONArray jsonArray = new JSONArray(json);
        Iterator iterator = jsonArray.iterator();
        ArrayList<ArrayList<String>> arrayList = new ArrayList<>();
        List<String> coreData = new ArrayList<>();// db value

        ArrayList<ArrayList<String>> coreArrayList = new ArrayList<>();
        List<Object[]> argsList = new ArrayList<>();

        while (!isStop&&iterator.hasNext()) {
            JSONObject userInfoResp = new JSONObject(iterator.next());
            String userName = userInfoResp.getStr("login");
            System.out.println("crawl>>>>>>>>>>>>>>>>>>"+userName+":repo>>>>>>>>>>>>>>>>>>>");
            System.out.println(userName);

            // 对仓库进行处理分析
            json = HttpUtil.createGet( REPO_INFO_URL.replace("username",userName))
                    .header("Authorization",LIMIT_TOKEN)
                    .execute().body();


            JSONArray jsonArray1 = new JSONArray(json);
            Iterator iterator1 = jsonArray1.iterator();

            System.out.println(userName+" repos size :"+jsonArray1.size());

            while (!isStop&&iterator1.hasNext()) {
                JSONObject jsonObject = new JSONObject(iterator1.next());
                //System.out.println(jsonObject);
                // 提取关键信息至数据库
                String language = jsonObject.getStr("language");
                String repoName = jsonObject.getStr("name");
                String description=jsonObject.getStr("description");
                Integer forks = jsonObject.getInt("forks");
                Integer stargazers_count  = jsonObject.getInt("stargazers_count");
                Integer issues = jsonObject.getInt("open_issues_count");
                Integer watchers = jsonObject.getInt("watchers");
                Integer size = jsonObject.getInt("size");
                String licenseName = jsonObject.getJSONObject("license").getStr("name");
                String createTime = jsonObject.getStr("created_at");
                String updateTime = jsonObject.getStr("updated_at");
                // ====
                System.out.println(userName+";"+repoName+";"+description+";"+language+";"+
                        forks+";"+stargazers_count+";"+issues+";"+watchers+";"+size+";"+licenseName+
                        ";"+createTime+";"+updateTime);
                // ====
                String saveToDbValue = "\""+userName + "\",\"" + repoName + "\"," + language+",\"" + description + "\","
                        + forks + "," + stargazers_count + "," + issues +"," + size + ",\"" + licenseName +"\"";
                        //","+ createTime + "," + updateTime;
                coreData.add(saveToDbValue);
                //persistService.batchInsert();

                // 魔法数
                Object[] args = new Object[9];
                args[0] = userName;
                args[1] = repoName;
                args[2] = language;
                args[3] = description;
                args[4] = forks;
                args[5] = stargazers_count;
                args[6] = issues;
                args[7] = size;
                args[8] = licenseName;
                argsList.add(args);

                ArrayList<String> row = new ArrayList<>();
                ArrayList<String> coreRow = new ArrayList<>();
                coreRow.add(userName);
                coreRow.add(repoName);
                coreRow.add(description);
                coreRow.add(language);
                coreRow.add(forks+"");
                coreRow.add(stargazers_count+"");
                coreRow.add(issues+"");
                coreRow.add(watchers+"");
                coreRow.add(size+"");
                coreRow.add(licenseName);
                coreRow.add(createTime);
                coreRow.add(updateTime);
                coreArrayList.add(coreRow);

                for(Object o:jsonObject.values()){
                    // 处理文件类型---
                    if(o instanceof Boolean){
                        row.add((Boolean) o ?"true":"false");
                        continue;
                    } else if(o instanceof Integer){
                        row.add(((Integer)o)+"");
                        continue;
                    } else if(o instanceof JSONObject || o instanceof JSONArray){
                        continue;
                    } else if(o instanceof JSONNull){
                        row.add("");
                        continue;
                    }
                    row.add((String) o);
                }
                // 完整的信息 保存文件---
                arrayList.add(row);

            }

            if(!iterator.hasNext()){
                // 为空了 需要发起新的请求
                int firstIndex = index;
                index = userInfoResp.getInt("id");

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                System.out.println("save to file>>>>");
                // 异步处理
                //arrayList.add(null);// 空行
                // 注意测试路径的正确性
                ///savePathPrefix.endsWith("\\")
                if(persistService==null){
                    // dont save to db
                }else{
                   // persistService.batchInsert(coreData);
                    CCLabThreadManager.executeService(()->{
                        persistService.batchInsertByArgs(argsList);
                    });
                }

                int finalIndex = index;
                CCLabThreadManager.executeService(()->{
                    FileUtil.saveToFile(arrayList,savePathPrefix+"\\repo_info_"+firstIndex+"_"+ finalIndex +".csv",null);
                });
                //System.out.println(coreArrayList.size()+"::"+coreArrayList);

                // FIXME 为何文件会为空？
                //java.lang.NullPointerException
                //	at com.nju.crawler.storage.FileUtil.delQuota(FileUtil.java:36)
                //CCLabThreadManager.executeService(()->{
                    FileUtil.saveToFile(coreArrayList,savePathPrefix+"\\repo_core_info_"+firstIndex+"_"+ finalIndex +".csv",null);
                //});

                System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                System.out.println(">>>>>>>>>>>>>>>start new crawl (new index:"+index+")>>>>>>>>>>>>>>>>>>>>");
                crawl(index);
            }

        }
    }

    @Override
    public void execute() {
        crawl(startIndex);
    }

    @Override
    public void stop() {
       this.isStop = true;
       System.out.println("stop task-"+getClass().getName());
    }
}
